import { fileUpload } from '@/api/FileApi.ts'
import { FileItem } from '@/component/Upload/types'
import { ArrayTool } from '@es-tool/core'
import { computed, onBeforeUnmount, ref, type Ref, watch } from 'vue'

type PropsType = {
    limit?: number
    uri?: Array<string> | string
    fileId?: Array<string> | string
}

type EmitsType = {
    (event: 'update:uri', value: Array<string> | string): void
    (event: 'update:fileId', value: Array<string> | string): void
    (event: 'change'): void
}

export class UploadService {

    /**
     * 文件列表
     */
    public readonly fileList: Ref<Array<FileItem>> = ref([])

    /**
     * 上传中
     */
    public readonly uploading =
            computed(() => this.fileList.value.some(i => i.status === '上传中'))

    /**
     * 多选模式
     */
    public readonly multiple =
            computed(() => this.props.limit! > 1)

    /**
     * 显示上传按钮
     */
    public readonly showUploadBtn =
            computed(() => this.fileList.value.length < this.props.limit!)

    /**
     * Input DOM 引用
     */
    private readonly inputRef: Ref<HTMLInputElement | null>

    /**
     * 选择的文件
     */
    private readonly selectedFile: Ref<Array<File>> = ref([])

    /**
     * 中断上传请求
     */
    private abortUploadRequest: Array<Function> = []

    private readonly props: PropsType

    private readonly emits: EmitsType


    /**
     * 构造函数
     */
    public constructor(props: PropsType, emits: EmitsType, inputRef: Ref<HTMLInputElement | null>) {
        this.props = props
        this.emits = emits
        this.inputRef = inputRef

        this.onBtnClick = this.onBtnClick.bind(this)
        this.onSelect = this.onSelect.bind(this)
        this.onRemoveItem = this.onRemoveItem.bind(this)
        this.clearFileList = this.clearFileList.bind(this)

        onBeforeUnmount(() => {
            this.clearFileList()
            for (const fun of this.abortUploadRequest) {
                fun()
            }
        })

        watch(() => this.props.uri, () => this.echo(), { immediate: true })
    }

    private echo(): void {
        const { uri } = this.props
        const arr = Array.isArray(uri) ? uri : [ uri ]

        if (!uri || ArrayTool.isEmpty(arr)) {
            this.fileList.value = []
            return
        }
        // 非空时忽略外部传入
        if (ArrayTool.isNotEmpty(this.fileList.value)) {
            return
        }
        this.fileList.value = arr
                .map(i => {
                    if (!i) {
                        return null
                    }
                    return FileItem.ofUri(i)
                })
                .filter(i => !!i)
    }

    /**
     * 上传按钮
     */
    public onBtnClick(): void {
        if (this.uploading.value) {
            return
        }
        this.inputRef.value?.click()
    }

    /**
     * 选择文件后
     */
    public onSelect(): void {
        this.clearFileList()

        const files: Array<File> = Array.from(this.inputRef.value?.files ?? [])
        this.selectedFile.value = files.slice(0, this.props.limit!)
        for (const file of this.selectedFile.value) {
            this.fileList.value.push(FileItem.ofFile(file))
        }
        this.startUpload()
    }

    public startUpload(): void {
        const arr = this.fileList.value
        if (ArrayTool.isEmpty(arr)) {
            return
        }

        for (const fileItem of arr) {
            const controller = new AbortController()

            fileUpload({
                file: fileItem.file!,
                originalName: fileItem.name!,
                abortController: controller,
                onUploadProgress: (event) => {
                    fileItem.status = '上传中'
                    fileItem.percent = event.progress
                },
            })
                    .then(res => {
                        fileItem.response = res
                        fileItem.url = res.url.url
                        fileItem.status = '完成'
                        this.emitValue()
                    })
                    .catch(error => {
                        fileItem.status = '错误'
                        console.debug(error)
                    })
            this.abortUploadRequest.push(() => controller.abort())
        }

    }

    public onRemoveItem(item: FileItem) {
        const index = this.fileList.value.findIndex(i => i === item)
        if (index >= 0) {
            const removed = this.fileList.value.splice(index, 1)
            removed.forEach(i => i.clear())
            this.emitValue()
        }
    }

    /**
     * 清空文件列表 并释放资源文件
     */
    public clearFileList(): void {
        for (const item of this.fileList.value) {
            item.clear()
        }
        this.fileList.value = []
    }

    private emitValue(): void {
        const uriArr: Array<string> = this.fileList.value
                .filter(i => i.status === '完成')
                .map(i => i.response?.uri)
        if (this.multiple.value) {
            this.emits('update:uri', uriArr)
        } else {
            this.emits('update:uri', uriArr[0] ?? '')
        }

        const idArr: Array<string> = this.fileList.value
                .filter(i => i.status === '完成')
                .map(i => i.response?.id)
        if (this.multiple.value) {
            this.emits('update:fileId', idArr)
        } else {
            this.emits('update:fileId', idArr[0] ?? '')
        }

        this.emits('change')
    }


}
